//
//  QTemplet.m
//  ImageEffect
//
//  Created by lichq on 14-1-16.
//  Copyright (c) 2014年 lichq. All rights reserved.
//

#import "QTemplet.h"
#import "QRegionColor.h"

#define GAP 8

@implementation QTemplet

unsigned char *QScaleImagePixel(QImagePixelInfo imagePixelInfo, int newW, int newH){
    unsigned char *imagePixel = imagePixelInfo.imagePixel;
    int oldW = imagePixelInfo.imageW;
    int oldH = imagePixelInfo.imageH;
    long oldStartByte = 0;
    
    int length = newH * newW * 4;
    unsigned char *newImagePixel = (unsigned char *)calloc(length, sizeof(unsigned char));
    int newY, newX;
    long newStartByte;
    
    for(int y = 0;y < oldH; y++)
	{
		for (int x = 0; x < oldW; x++)
		{
            newY = y * newH / oldH;
            newX = x * newW / oldW;
            
            oldStartByte = (y * oldW +x) * 4;
            newStartByte = (newY * newW + newX) * 4;
            
            newImagePixel[newStartByte] = imagePixel[oldStartByte];
            newImagePixel[newStartByte+1] = imagePixel[oldStartByte+1];
            newImagePixel[newStartByte+2] = imagePixel[oldStartByte+2];
            newImagePixel[newStartByte+3] = imagePixel[oldStartByte+3];
        }
    }
    return newImagePixel;
}

unsigned char *QScaleImagePixelFitRegion(QImagePixelInfo imagePixelInfo, QRegionInfo *regionInfo, int region){
    int regionXMin = regionInfo[region].xmin;
    int regionXMax = regionInfo[region].xmax;
    int regionYMin = regionInfo[region].ymin;
    int regionYMax = regionInfo[region].ymax;
    
    int newW = regionXMax - regionXMin;
    int newH = regionYMax - regionYMin;
    
    unsigned char *newImagePixel = QScaleImagePixel(imagePixelInfo, newW, newH);
    return newImagePixel;
    
    /*
    unsigned char *imagePixel = imagePixelInfo.imagePixel;
    int oldW = imagePixelInfo.imageW;
    int oldH = imagePixelInfo.imageH;
    long oldStartByte = 0;
    
    int length = newH * newW * 4;
    unsigned char *newImagePixel = (unsigned char *)calloc(length, sizeof(unsigned char));
    int newY, newX;
    long newStartByte;
    
    for(int y = 0;y < oldH; y++)
	{
		for (int x = 0; x < oldW; x++)
		{
            newY = y * newH / oldH;
            newX = x * newW / oldW;
            
            oldStartByte = (y * oldW +x) * 4;
            newStartByte = (newY * newW + newX) * 4;
            
            newImagePixel[newStartByte] = imagePixel[oldStartByte];
            newImagePixel[newStartByte+1] = imagePixel[oldStartByte+1];
            newImagePixel[newStartByte+2] = imagePixel[oldStartByte+2];
            newImagePixel[newStartByte+3] = imagePixel[oldStartByte+3];
        }
    }
    return newImagePixel;
    */
}

QTempletInfo QFillImageToTempletInRegion(QImagePixelInfo imagePixelInfo, QTempletInfo templetInfo, int region){
    if (region >= templetInfo.regionCount) {
        NSLog(@"Error: region is out of regionCount");
    }
    unsigned char *templetPixel = templetInfo.templetPixel;
    
    int *regionPixelPosition = templetInfo.regionInfo[region].regionPosition;
    int *xarray = templetInfo.regionInfo[region].x;
    int *yarray = templetInfo.regionInfo[region].y;
    
    int regionXMin = templetInfo.regionInfo[region].xmin;
    int regionXMax = templetInfo.regionInfo[region].xmax;
    int regionYMin = templetInfo.regionInfo[region].ymin;
    int regionYMax = templetInfo.regionInfo[region].ymax;
    
    int newW = regionXMax - regionXMin + 1; //be care for add 1
    int newH = regionYMax - regionYMin + 1;
    
    
    //Todo按比例缩放并添加居中时要移动的变量
    int newWTemp = regionXMax - regionXMin + 1;
    int newHTemp = regionYMax - regionYMin + 1;
    int offsetX = 0, offsetY = 0;
//    /*
    if (newWTemp * imagePixelInfo.imageH > newHTemp * imagePixelInfo.imageW) {
        newW = newWTemp;
        newH = newW * imagePixelInfo.imageH / imagePixelInfo.imageW;
        offsetY = (newH - newHTemp)/2;
    }else if (newWTemp * imagePixelInfo.imageH < newHTemp * imagePixelInfo.imageW) {
        newH = newHTemp;
        newW = newH * imagePixelInfo.imageW / imagePixelInfo.imageH;
        offsetX = (newW - newWTemp)/2;
    }
//    */
    
    unsigned char *imagePixel = QScaleImagePixel(imagePixelInfo, newW, newH);
    
    int pixelCount = templetInfo.regionInfo[region].pCount;

    for (int i = 0; i < pixelCount; i++) {
        int startByte = regionPixelPosition[i] * 4;
        
//        int y = regionPixelPosition[i]/templetInfo.templetW - regionYMin;
//        int x = regionPixelPosition[i]%templetInfo.templetW - regionXMin;
//        int y = yarray[i] - regionYMin;
//        int x = xarray[i] - regionXMin;
        int y = yarray[i] - regionYMin + offsetY;
        int x = xarray[i] - regionXMin + offsetX;
        
        int startByte1 = (y * newW + x) * 4;
        
        
        
        templetPixel[startByte] = imagePixel[startByte1];
        templetPixel[startByte+1] = imagePixel[startByte1+1];
        templetPixel[startByte+2] = imagePixel[startByte1+2];
        templetPixel[startByte+3] = imagePixel[startByte1+3];
    }
//    return templetPixel;
    templetInfo.templetPixel = templetPixel;
    
    templetInfo.regionInfo[region].existImage = true;
    return templetInfo;
}




#pragma mark - Create Templet
bool isCuPixelColorEqualRegionColor(unsigned char *templetPixel, int x, int y, int w, float *regionColor){
    int startByte = (y*w+x) * 4;
    int red = templetPixel[startByte];
    int green = templetPixel[startByte+1];
    int blue = templetPixel[startByte+2];
    int alpha = templetPixel[startByte+3];
    if(red == regionColor[0] && green == regionColor[1] && blue == regionColor[2] && alpha == regionColor[3]){
        return true;
    }
       return false;
}

void updateTempletInfoInXY(QTempletInfo *pTempletInfo, int x, int y, float *QRegionColor[], int region, bool *isFirst){
    QTempletInfo templetInfo = *pTempletInfo;
    
    unsigned char *templetPixel = templetInfo.templetPixel;
    
    int startByte = (y * templetInfo.templetW + x) * 4;
    for (int i = 0; i < 4; i++) {
        templetPixel[startByte + i] = QRegionColor[region][i];
    }
    
//    pTempletInfo = &templetInfo;
    
    updateRegionInfoByXY(&templetInfo.regionInfo, region, x, y, templetInfo.templetW, isFirst);
}



void updateRegionInfoByXY(QRegionInfo **pRegionInfo, int region, int x , int y, int w, bool *isFirstUpdate){
    QRegionInfo *regionInfo = *pRegionInfo;
    
    if (*isFirstUpdate) {
        regionInfo[region].xmin = x;
        regionInfo[region].xmax = x;
        regionInfo[region].ymin = y;
        regionInfo[region].ymax = y;
        *isFirstUpdate = false;
    }else{
        regionInfo[region].xmin = MIN(regionInfo[region].xmin, x);
        regionInfo[region].xmax = MAX(regionInfo[region].xmax, x);
        regionInfo[region].ymin = MIN(regionInfo[region].ymin, y);
        regionInfo[region].ymax = MAX(regionInfo[region].ymax, y);
    }
    

    int curPCount = regionInfo[region].pCount;
    regionInfo[region].regionPosition[curPCount] = y * w + x;
    regionInfo[region].x[curPCount] = x;
    regionInfo[region].y[curPCount] = y;
    
    regionInfo[region].pCount ++;
    
    
    pRegionInfo = &regionInfo;
}

QTempletInfo newTempletInfo(int templetW, int templetH, int regionCount){
    int length = templetW * templetH * 4;
    unsigned char *templetPixel = (unsigned char *)calloc(length, sizeof(unsigned char));
    for (int i = 0; i<length; i++) {
        templetPixel[i]=255;
    }
    
    
    int pixelCount = templetW * templetH;
    QRegionInfo *regionInfo = (QRegionInfo *)calloc(regionCount, sizeof(QRegionInfo));  //QRegionInfo regionInfo[3] = {0};
    for (int region = 0; region < regionCount; region++) {
        regionInfo[region].regionPosition = (int *)calloc(pixelCount, sizeof(int));
        regionInfo[region].x = (int *)calloc(pixelCount, sizeof(int));
        regionInfo[region].y = (int *)calloc(pixelCount, sizeof(int));
        
        regionInfo[region].existImage = false;
    }
    
    QTempletInfo templetInfo;
    templetInfo.templetPixel = templetPixel;
    templetInfo.templetW = templetW;
    templetInfo.templetH = templetH;
    
    templetInfo.regionCount = regionCount;
    templetInfo.regionInfo = regionInfo;
    
    return templetInfo;
}

/*
QTempletInfo copyQTempletInfo(QTempletInfo cInfo){
    QTempletInfo dInfo = newTempletInfo(cInfo.templetW, cInfo.templetH, cInfo.regionCount);
    dInfo.regionCount = cInfo.regionCount;
    dInfo.templetW = cInfo.templetW;
    dInfo.templetH = cInfo.templetH;
    
    //dInfo.templetPixel = *cInfo.templetPixel;
    //dInfo.templetPixel = cInfo.templetPixel;
    
    //int length =  strlen(cInfo.templetPixel);
    int templetW = cInfo.templetW;
    int templetH = cInfo.templetH;
    int length = templetW * templetH * 4;
    unsigned char *templetPixel = (unsigned char *)calloc(length, sizeof(unsigned char));
    for (int i = 0; i<length; i++) {
        templetPixel[i] = cInfo.templetPixel[i];
    }
    dInfo.templetPixel = templetPixel;
    
    
    dInfo.regionInfo = cInfo.regionInfo;
    for (int i = 0 ; i < cInfo.regionCount; i++) {
        dInfo.regionInfo[i].regionPosition = cInfo.regionInfo[i].regionPosition;
        dInfo.regionInfo[i].x = cInfo.regionInfo[i].x;
        dInfo.regionInfo[i].y = cInfo.regionInfo[i].y;
        
        dInfo.regionInfo[i].pCount = cInfo.regionInfo[i].pCount;
        
        dInfo.regionInfo[i].xmax = cInfo.regionInfo[i].xmax;
        dInfo.regionInfo[i].xmin = cInfo.regionInfo[i].xmin;
        dInfo.regionInfo[i].ymax = cInfo.regionInfo[i].ymax;
        dInfo.regionInfo[i].ymin = cInfo.regionInfo[i].ymin;
        
        dInfo.regionInfo[i].existImage = cInfo.regionInfo[i].existImage;
    }
    return dInfo;
}
*/

QTempletInfo createTempletInfo0(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 3;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    /*
    int length = w * h * 4;
    unsigned char *templetPixel = (unsigned char *)calloc(length, sizeof(unsigned char));
    for (int i = 0; i<length; i++) {
        templetPixel[i]=255;
    }
    
    int pixelCount = w * h;
    QRegionInfo *regionInfo = (QRegionInfo *)calloc(regionCount, sizeof(QRegionInfo));  //QRegionInfo regionInfo[3] = {0};
    for (int region = 0; region < regionCount; region++) {
        regionInfo[region].regionPosition = (int *)calloc(pixelCount, sizeof(int));
        regionInfo[region].x = (int *)calloc(pixelCount, sizeof(int));
        regionInfo[region].y = (int *)calloc(pixelCount, sizeof(int));
    }
    
    QTempletInfo templetInfo;
    templetInfo.templetPixel = templetPixel;
    templetInfo.templetW = w;
    templetInfo.templetH = h;
    templetInfo.regionInfo = regionInfo;
//    */
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {

            if (y < (2*h*x)/(3*w) + h/3- GAP/2 && y < -(2*h*x)/(3*w) + h - GAP/2){
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
                
                /*
                int i = (y*w+x) * 4;
                templetPixel[i] = QRegionColor[region][0];
                templetPixel[i+1] = QRegionColor[region][1];
                templetPixel[i+2] = QRegionColor[region][2];
                templetPixel[i+3] = QRegionColor[region][3];
                */
                
                //updateRegionInfoByXY(&regionInfo, region, x, y, w, &isFirstUpdate[region]);
                /*
                if (isFirstUpdate[region]) {
                    regionInfo[region].xmin = x;
                    regionInfo[region].xmax = x;
                    regionInfo[region].ymin = y;
                    regionInfo[region].ymax = y;
                    isFirstUpdate[region] = false;
                }else{
                    regionInfo[region].xmin = MIN(regionInfo[region].xmin, x);
                    regionInfo[region].xmax = MAX(regionInfo[region].xmax, x);
                    regionInfo[region].ymin = MIN(regionInfo[region].ymin, y);
                    regionInfo[region].ymax = MAX(regionInfo[region].ymax, y);
                }
                
                int curPCount = regionInfo[region].pCount;
                if (curPCount < pixelCount) {
                    regionInfo[region].regionPosition[curPCount] = y*w+x;
                    regionInfo[region].x[curPCount] = x;
                    regionInfo[region].y[curPCount] = y;
                 
                    regionInfo[region].pCount++;
                }
                */
            }else if (y > (2*h*x)/(3*w) + h/3 + GAP/2 || y > -(2*h*x)/(3*w) + h + GAP/2){
                if (x< w/2 - GAP/2) {
                    region = 1;
                    updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
                }else if(x > w/2 + GAP/2){
                    region = 2;
                    updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
                }
            }
        }
    }
    //NSLog(@"templet0 = %d, %d, %d", templetInfo.regionInfo[0].pCount, templetInfo.regionInfo[1].pCount, templetInfo.regionInfo[2].pCount);
    
    return templetInfo;
}

QTempletInfo createTempletInfo1(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < h/2 - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > h/2 + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    

    
    return templetInfo;
}

QPoint getKDByPoint(QPoint p1, QPoint p2){
    int k = 0;
    if (p2.x == p1.x) {
        k = 0;
    }else{
        k = (p2.y - p1.y) / (p2.x - p1.x);
    }
    int d = p2.y - k *p2.x;
    
    QPoint lineInfo = {k, d};
    return lineInfo;
}

bool boolXYInLine1(int x, int y, int w , int h, bool lineSmall){
    if (lineSmall) {
        if (x < w/3 - GAP/2) {
            return true;
        }
    }else{
        if (x > w/3 + GAP/2) {
            return true;
        }
    }
    
    return false;
}

QTempletInfo createTempletInfo2(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 5;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
//    QPoint p1tr = {w/3,0};
//    QPoint p1br = {w/3,h/3};
//    QPoint l1r = getKDByPoint(p1tr, p1br);
//    
//    QPoint p1bl = {0,h/3};
//    QPoint l1b = getKDByPoint(p1bl, p1br);
    
    
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
//            if (x < w/3 - GAP/2 && y < h/3 - GAP/2) {
            if (boolXYInLine1(x, y, w, h, true) && y < h/3 - GAP/2) {
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, 0, &isFirstUpdate[0]);
            }else if(x > w/3 + GAP/2 || y > h/3 + GAP/2){
                if (y < h/3 - GAP/2) {
                    updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, 1, &isFirstUpdate[1]);
                }else if(y > h/3 + GAP/2){
                    if (y < 2*h/3 - GAP/2) {
                        updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, 2, &isFirstUpdate[2]);
                    }else if (y > 2*h/3 + GAP/2) {
                        if (x < 2*w/3 - GAP/2) {
                            updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, 3, &isFirstUpdate[3]);
                        }else if (x > 2*w/3 + GAP/2) {
                            updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, 4, &isFirstUpdate[4]);
                        }
                    }
                }
            }
        }
    }
    
    return templetInfo;
}

QTempletInfo createTempletInfo3(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    

    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    QPoint p1 = {0,0};
    QPoint p2 = {20,20};
    QPoint l1 = getKDByPoint(p1, p2);
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < l1.x * x + l1.y - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > l1.x * x + l1.y + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    
    return templetInfo;
}

QTempletInfo createTempletInfo4(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    QPoint p1 = {0,0};
    QPoint p2 = {20,20};
    QPoint l1 = getKDByPoint(p1, p2);
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < l1.x * x + l1.y - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > l1.x * x + l1.y + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    
    return templetInfo;
}

QTempletInfo createTempletInfo5(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    QPoint p1 = {0,0};
    QPoint p2 = {20,20};
    QPoint l1 = getKDByPoint(p1, p2);
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < l1.x * x + l1.y - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > l1.x * x + l1.y + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    
    return templetInfo;
}

QTempletInfo createTempletInfo6(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    QPoint p1 = {0,0};
    QPoint p2 = {20,20};
    QPoint l1 = getKDByPoint(p1, p2);
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < l1.x * x + l1.y - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > l1.x * x + l1.y + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    
    return templetInfo;
}

QTempletInfo createTempletInfo7(){
    int Size = 110;
    int w = 2*Size;
    int h = 3*Size;
    int regionCount = 2;
    
    
    QTempletInfo templetInfo = newTempletInfo(w, h, regionCount);
    
    bool *isFirstUpdate = (bool *)calloc(regionCount, sizeof(bool));
    for (int region = 0; region < regionCount; region++) {
        isFirstUpdate[region] = true;
    }
    
    int region = 0;
    QPoint p1 = {0,0};
    QPoint p2 = {20,20};
    QPoint l1 = getKDByPoint(p1, p2);
    
    for (int y = GAP; y < h-GAP; y++) {
        for (int x = GAP; x < w-GAP; x++) {
            
            if (y < l1.x * x + l1.y - GAP/2) {
                region = 0;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }else if(y > l1.x * x + l1.y + GAP/2){
                region = 1;
                updateTempletInfoInXY(&templetInfo, x, y, QRegionColor, region, &isFirstUpdate[region]);
            }
        }
    }
    
    return templetInfo;
}

@end
